<script lang="ts" setup>
import type Node from "element-plus/es/components/tree/src/model/node";
import { SForm } from "#components";

// 使用索引签名定义对象类型
type GenericObject = {
  [key: string]: any;
};

interface Tree {
  code: string;
  label: string;
  children?: Tree[];
}

const editFormRef = ref<InstanceType<typeof SForm> | null>(null);

const callbackMessage = useCallbackMessage();
const callbackMessage_dialog = useCallbackMessage();
let old_unique = "";
const PageConfig = {
  //被操作实体的名称
  entity: "system",
  api: {
    //获取列表数据
    list: "/list",
  },
};
const action = ref("list");
const id = ref("");
const editType = ref("");
const dialogVisible = ref(false);

const Model: {
  [key: string]: any;
} = {
  label: {
    label: "部门名称",
    require: true,
  },
  code: {
    label: "部门编码",
    require: true,
  },
};
const dataSource = ref<GenericObject[]>([]);
let handle_data: GenericObject = {};

const getList = async () => {
  action.value = "list";
  const res: {
    [key: string]: any;
  }[] = await $fetch(`/api/${PageConfig.entity}${PageConfig.api.list}`, {
    query: {
      name: "department",
    },
  });
  if (Array.isArray(res) && res.length > 0) {
    dataSource.value = JSON.parse(res[0].content);
    id.value = res[0]._id;
  } else {
    try {
      await $fetch(`/api/system/add`, {
        body: {
          name: "department",
          content: JSON.stringify([]),
        },
        method: "POST",
      });
      saveOK();
    } catch (e: any) {
      callbackMessage.value = {
        show: true,
        valid: false,
        content: "部门初始化失败",
      };
    }
  }
};

const handle_add = async (data: Tree, node: Tree) => {
  action.value = "add";
  old_unique = "";
  editType.value = "addChild";
  dialogVisible.value = true;
  handle_data = data;
  await nextTick();
  if (editFormRef.value) {
    editFormRef.value.localFormData = {};
  }
};

const handle_edit = async (data: Tree) => {
  action.value = "edit";
  editType.value = "";
  dialogVisible.value = true;
  old_unique = data.code;
  handle_data = data;
  await nextTick();
  if (editFormRef.value) {
    editFormRef.value.localFormData = JSON.parse(JSON.stringify(data));
  }
};

const handle_del = (node: Node, data: Tree) => {
  const parent = node.parent;
  const children: Tree[] = parent.data.children || parent.data;
  const index = children.findIndex((d) => d.code === data.code);
  children.splice(index, 1);
  dataSource.value = [...dataSource.value];
  saveToDB();
};

const addTop = () => {
  action.value = "add";
  editType.value = "addTop";
  if (editFormRef.value) {
    editFormRef.value!.localFormData = {};
  }
  dialogVisible.value = true;
};

const save = async () => {
  if (editFormRef.value) {
    let new_unique = editFormRef.value.localFormData.code;
    if (
      old_unique !== new_unique &&
      hasTargetValueInTree(dataSource.value, "code", new_unique)
    ) {
      callbackMessage_dialog.value = {
        show: true,
        valid: false,
        content: "部门编码已存在，请修改后重试",
      };
      return;
    }
    editFormRef.value.submitForm(editFormRef.value.formRef);
  }
};

const saveToDB = async (formData?: GenericObject) => {
  let old_dataSource = JSON.parse(JSON.stringify(dataSource.value));
  if (formData) {
    if (editType.value === "addTop") {
      dataSource.value.unshift(formData);
    }
    if (editType.value === "addChild") {
      const newChild = formData;
      if (!handle_data.children) {
        handle_data.children = [];
      }
      handle_data.children.push(newChild);
    }
    if (action.value === "edit") {
      handle_data.label = formData.label;
      handle_data.code = formData.code;
    }
  }
  try {
    await $fetch(`/api/system/edit`, {
      body: {
        _id: id.value,
        name: "department",
        content: JSON.stringify(dataSource.value),
      },
      method: "POST",
    });
    callbackMessage.value = {
      show: true,
      valid: true,
      content: "操作成功",
    };
    saveOK();
  } catch (e: any) {
    callbackMessage.value = {
      show: true,
      valid: false,
      content: e.data.message,
    };
    dataSource.value = JSON.parse(JSON.stringify(old_dataSource));
  }
};

const saveOK = () => {
  editType.value === "";
  getList();
  setTimeout(() => {
    dialogVisible.value = false;
  }, 500);
};

const handle_drop = async () => {
  saveToDB();
};

onMounted(() => {
  getList();
});
</script>
<template>
  <div class="flex flex-col items-center fullParent overflow-auto pt-10">
    <el-dialog v-model="dialogVisible" width="600" title="编辑部门">
      <S-form
        v-if="dialogVisible"
        ref="editFormRef"
        hideHandle
        :Model="Model"
        :colNum="1"
        :local_save="saveToDB"
      />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="save"> 保存 </el-button>
        </div>
      </template>
      <S-msgWin top="20%" :msg="callbackMessage_dialog" />
    </el-dialog>
    <el-button type="primary" @click="addTop"> 添加顶级部门 </el-button>
    <el-tree
      class="mt4"
      style="min-width: 600px"
      :data="dataSource"
      node-key="code"
      accordion
      draggable
      default-expand-all
      :expand-on-click-node="false"
      :indent="32"
      @node-drop="handle_drop"
    >
      <template #default="{ node, data }">
        <div class="custom-tree-node">
          <div
            class="flex items-center gap-2"
            :class="{
              'font-bold': node.level === 1,
              'text-4': node.level === 1,
            }"
          >
            <S-icon v-if="data.icon" :icon="data.icon" />
            <div>
              {{ node.label }}
            </div>
          </div>
          <div>
            <el-button
              type="primary"
              link
              @click="handle_add(data, node)"
              :disabled="data.noChild"
            >
              <S-icon icon="material-symbols-light:add-rounded" />
              <span class="ml2">添加</span>
            </el-button>
            <el-button
              class="ml4"
              type="primary"
              link
              @click="handle_edit(data)"
            >
              <S-icon icon="line-md:edit-twotone" />
              <span class="ml2">修改</span>
            </el-button>
            <el-popconfirm
              title="确定删除吗?"
              @confirm="handle_del(node, data)"
            >
              <template #reference>
                <el-button class="ml4" type="danger" link>
                  <S-icon icon="wpf:delete" />
                  <span class="ml2">删除</span>
                </el-button>
              </template>
            </el-popconfirm>
          </div>
        </div>
      </template>
    </el-tree>
    <S-msgWin top="20%" :msg="callbackMessage" />
  </div>
</template>
<style scoped>
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
.fullParent {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
:deep(.el-tree-node) {
  margin-top: 12px;
}
</style>
